﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ConciseMarkupLanguage.Utils;
using Irony.Ast;
using Irony.Interpreter;
using Irony.Parsing;

namespace ConciseMarkupLanguage.Ast
{
    class TermFilterNode : AstNode
    {
        private AstNode termNode;
        private FilterNode filterNode;

        public override void Init(ParsingContext context, ParseTreeNode treeNode)
        {
            base.Init(context, treeNode);
            termNode = AddChild("term", treeNode.ChildNodes[0]);
            filterNode = (FilterNode)AddChild("filter", treeNode.ChildNodes.Last());
        }

        public override void EvaluateNode(EvaluationContext context, AstMode mode)
        {
            termNode.Evaluate(context, AstMode.Read);
            var parameters = new List<object> { context.Data.Pop() };
            filterNode.Evaluate(context, AstMode.Read);
            if (context.Data.Count > 0)
                parameters.AddRange(((IEnumerable)context.Data.Pop()).Cast<object>());
            foreach (var p in CmlGrammar.Filters[filterNode.Function].GetParameters().Enumerate())
            {
                if (parameters.ContainsKey(p.Key))
                {
                    if (parameters[p.Key].GetType() != p.Value.ParameterType)
                        parameters[p.Key] = Convert.ChangeType(parameters[p.Key], p.Value.ParameterType);
                }
                else
                {
                    if (p.Value.DefaultValue is DBNull)
                        throw new Exception("Missing parameter '" + p.Value.Name + "' for filter '" + filterNode.Function + "' and no default exists.");
                    parameters.Add(p.Value.DefaultValue);
                }
            }
            var filtered = CmlGrammar.Filters[filterNode.Function].Invoke(null, parameters.ToArray());
            context.Data.Push(filtered);
        }
    }
}
